#include "web_shttpd.h"
#include <string.h>
#include "web_page.h"
#include <stdio.h>
#include <sys/stat.h> 
const int buflen = 1024;
const char * root_node = "/";
const char *path_root = "./web";

static char* get_content_type(const char* chrext)
{
	if (strcmp(chrext, ".html") == 0) {
		return "text/html";
	} else if (strcmp(chrext, ".htx") == 0){
		return "text/html";
	} else if (strcmp(chrext, ".jsp") == 0){
		return "text/html";
	} else if (strcmp(chrext, ".css") == 0){
		return "text/css";
	} else if (strcmp(chrext, ".ico") == 0) {
		return "image/x-icon";
	} else if (strcmp(chrext, ".jpe") == 0){
		return "image/jpeg";
	} else if (strcmp(chrext, ".jpeg") == 0){
		return "image/jpeg";
	} else if (strcmp(chrext, ".jpg") == 0){
		return "image/jpeg";
	} else if (strcmp(chrext, ".js") == 0){
		return "application/x-javascript";
	} else if (strcmp(chrext, ".png") == 0){
		return "application/x-png";
	}else
		return "";

}

static void  deal_http_message(struct shttpd_arg *arg) 
{
    if (arg == NULL)
		return;

	const char *request_method, *query_string, *request_uri, *request_addr;
	request_method = shttpd_get_env(arg, "REQUEST_METHOD");
	request_uri = shttpd_get_env(arg, "REQUEST_URI");
	query_string = shttpd_get_env(arg, "QUERY_STRING");
	request_addr = shttpd_get_env(arg, "REMOTE_ADDR");
	//printf("request_method:%s\n", request_method);
	//printf("request_uri:%s\n", request_uri);
	//printf("query_string:%s\n", query_string);
	//printf("request_addr:%s\n", request_addr);

	shttpd_printf(arg, "%s", "HTTP/1.1 200 OK\r\n"
	"X-Application-Context: application\r\n"
	"Access-Control-Allow-Origin: *\r\n"
	"Access-Control-Allow-Credentials: true\r\n"
	"Content-Type: application/json;charset=UTF-8\r\n"
	"\r\n");

	//test------------------
	if (strcmp(request_uri, "/deviceDataChanged") == 0)
	{
		char buf1[buflen];
		memset(buf1, 0, buflen);
		int len = (buflen > arg->in.len) ? arg->in.len : buflen;
		memcpy(buf1, arg->in.buf, len);


		printf("request_method:%s\n",request_method);
		printf("request_uri:%s\n",request_uri);
		printf("query_string:%s\n",query_string);
		printf("request_addr:%s\n",request_addr);
		printf("devinfo:%s\n", buf1);
		arg->flags |= SHTTPD_END_OF_OUTPUT;
		return;
	}

	//end-----------------------

	if (strcmp(request_method, "POST")) {
		/* If not all data is POSTed, wait for the rest */
		shttpd_printf(arg, "%s", "{\"status\":400,\"message\":\"Request method error.Please use post\"}");
		arg->flags |= SHTTPD_END_OF_OUTPUT;
		return;
	}

	if (arg->flags & SHTTPD_MORE_POST_DATA)
		return;
	
	struct event_data * ed = (struct event_data*)arg->user_data;
	if (ed == NULL || ed->event == NULL)
	{
		shttpd_printf(arg, "%s", "{\"status\":500,\"message\":\"Parameter error\"}");
		arg->flags |= SHTTPD_END_OF_OUTPUT;
		return;
	}

	char buf[buflen];
	memset(buf, 0, buflen);
	int len = (buflen > arg->in.len) ? arg->in.len : buflen;
	memcpy(buf, arg->in.buf, len);
	std::string strmsg(buf);
	std::string struri(request_uri);
	std::string strjson = ed->event->on_message(struri, strmsg);

	shttpd_printf(arg, "%s", strjson.c_str());

	arg->flags |= SHTTPD_END_OF_OUTPUT;
    return;
}

static void deal_http_err(struct shttpd_arg *arg)
{
    if (arg == NULL)
		return;
	const char* uri = shttpd_get_env(arg, "REQUEST_URI");
	char filename[1024];
	memset(filename, 0, 1024);
	snprintf(filename, 1023, "%s%s", path_root, uri);

	FILE *fp = fopen(filename, "r");
	if (fp == NULL) 
	{
		shttpd_printf(arg, "%s", "HTTP/1.1 404 NOT FOUND\r\n");
		arg->flags |= SHTTPD_END_OF_OUTPUT;
		return ;
	}

	struct stat statbuf;  
	stat(filename,&statbuf);  
	long fsize = statbuf.st_size;
	long state = (long)(arg->state);
	if (state >= fsize)
	{
		fclose(fp);
		arg->flags |= SHTTPD_END_OF_OUTPUT;
		return;
	}
	
	long buflen = fsize - state;
	char* buf = (char*)malloc(buflen + 1);
	memset(buf, 0, buflen + 1);
	fseek(fp, state, SEEK_SET);
	fread(buf, 1, buflen, fp);
	fclose(fp);

	if (state == 0) {
		char *ext = strrchr(filename,'.');//获取后缀名
		shttpd_printf(arg, "%s", "HTTP/1.1 200 OK\r\n"
		"X-Application-Context: application\r\n"
		"Access-Control-Allow-Origin: *\r\n"
		"Access-Control-Allow-Credentials: true\r\n");
		shttpd_printf(arg, "Content-Length: %d\r\n", fsize);
		shttpd_printf(arg, "%s%s", "Content-Type: ", get_content_type(ext));
		shttpd_printf(arg, "%s", "\r\n\r\n");
	}
	int i = 0;
	while (arg->out.num_bytes < arg->out.len) {
		arg->out.buf[arg->out.num_bytes++] = buf[i++];
		state++;
		if (state >= fsize) {
			//printf("filename:%s,fsize:%d, send:%d\n\n", filename, fsize, state);
			arg->flags |= SHTTPD_END_OF_OUTPUT;
			break;
		}
	}

	arg->state = (void *) state;

	if (buf)
		free(buf);
}

web_httpd::web_httpd(http_event *pevent)
{
    _event = NULL;
    _pctx = NULL;
    if (pevent)
        _event = pevent;
}

web_httpd::~web_httpd()
{
    if (_pctx)
        fini();
}

int web_httpd::init(int argc, char *argv[])
{
    _pctx = shttpd_init(argc, argv);
    if (_pctx == NULL)
        return -1;
    return 0;
}

void web_httpd::fini()
{
    shttpd_fini(_pctx);
}

int web_httpd::set_option(const char *opt, const char *val)
{
    return (shttpd_set_option(_pctx, opt, val)== true) ? 0 : -1;
}

void web_httpd::register_uri(const char *uri, void *const user_data)
{
    struct event_data* ev_data = new struct event_data;
    ev_data->uritype = get_uri_type(uri);
    ev_data->data = user_data;
    ev_data->event = _event;
    shttpd_register_uri(_pctx, uri, deal_http_message, ev_data);
}

void web_httpd::web_poll(int milliseconds)
{
    shttpd_poll(_pctx, milliseconds);
}

const char *web_httpd::version(void)
{
    return shttpd_version(); //是宏定义的，无需释放空间
}

int web_httpd::get_var(const char *var, const char *buf, int buf_len, char *value, int value_len)
{
	return shttpd_get_var(var, buf, buf_len, value, value_len);
}

const char *web_httpd::web_get_header(struct shttpd_arg * arg, const char *header_name)
{
    return shttpd_get_header(arg, header_name);
}

const char *web_httpd::web_get_env(struct shttpd_arg *arg, const char *name)
{
    return shttpd_get_env(arg, name);
}

void web_httpd::get_http_version(struct shttpd_arg *arg, unsigned long *major, unsigned long *minor)
{
    shttpd_get_http_version(arg, major, minor);
}

size_t web_httpd::web_printf(struct shttpd_arg *arg, const char *fmt, ...)
{
    //return shttpd_printf(arg, fmt, ...)
    int buflen = 1024;
	char buf[buflen];
	memset(buf, 0, buflen);
    va_list	ap;
    if (buflen > 0) {
        va_start(ap, fmt);
        vsnprintf(buf, buflen, fmt, ap);
        va_end(ap);
    }
    return web_printf(arg, "%s", buf);
}

void web_httpd::handle_error(int status, void *const data)
{
    struct err_data* err_data = new struct err_data;
    err_data->err = status;
    err_data->data = data;
    err_data->event = _event;
    shttpd_handle_error(_pctx, status, deal_http_err, err_data);
}

void web_httpd::register_ssi_func(const char *name, void *const user_data)
{

}

void web_httpd::wakeup(const void *priv)
{
    shttpd_wakeup(priv);
}

int web_httpd::web_join(fd_set * read_set, fd_set *write_set, int *max_fd)
{
    return shttpd_join(_pctx, read_set, write_set, max_fd);
}

int  web_httpd::socketpair(int sp[2])
{
    return shttpd_socketpair(sp);
}


URI_TYPE web_httpd::get_uri_type(const char *uri)
{
    if (uri == NULL)
        return INVALID;

    if (strcmp(uri, root_node) == 0)
        return ROOT_BODE;
    //else if (strcmp(uri, ....) == 0)
    //    return ....;
    
    return INVALID;
    
}




